/* 
 * Copyright 2011 kOSMik.
 * This file is part of kOSMik.
 * 
 * kOSMik is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * kOSMik is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with kOSMik.  If not, see <http://www.gnu.org/licenses/>.
 *  
 * kOSMik:
 * Open Street Map - Editor.
 * http://code.google.com/p/swp-dv-ws2010-osm-2/
 */

package de.fuberlin.kosmik.data.osmt;

import java.util.HashMap;

import android.content.ContentValues;
import android.database.Cursor;
import de.fuberlin.kosmik.StrUtils;

/**
 * This class maps a row of the OsmtNodeLangText table to an object.
 * 
 * @author Johannes
 * 
 */
public class OsmtNodeLangText implements OsmtTable {

	/** Name of table OsmtNodeLangText. */
	static final String TABLE = "NodeLangText";
	/** 1. Column name. */
	static final String COLUMN_NODE_ID = "NodeLangText.node_id";
	/** 2. Column name. */
	static final String COLUMN_LANGUAGE = "NodeLangText.language";
	/** 3. Column name. */
	static final String COLUMN_DISPLAY_NAME = "NodeLangText.display_name";
	/** 4. Column name. */
	static final String COLUMN_COMMENT = "NodeLangText.comment";
	private final OsmtDatabase osmtDatabase;
	private final OsmtNodeLangTextRecord record = new OsmtNodeLangTextRecord();

	public OsmtNodeLangText(OsmtData osmtData, int nodeId, String language, String displayName,
			String comment) throws OsmtObjectException {
		super();
		this.osmtDatabase = ((OsmtDataImpl) osmtData).getDatabase();
		if (!set(nodeId, language, displayName, comment)) {
			throw new OsmtObjectException(
					String.format(
							"can neither load nor create %s text dependend attributes for node with id %d.",
							language, nodeId));
		}

	}

	public OsmtNodeLangText(OsmtData osmtData, OsmtNodeLangTextRecord nodeLangTextRecord)
			throws OsmtObjectException {
		this(osmtData, nodeLangTextRecord.nodeId, nodeLangTextRecord.language,
				nodeLangTextRecord.displayName, nodeLangTextRecord.comment);
	}

	void setTrusted(OsmtNodeLangTextRecord nodeLangTextRecord) {
		record.nodeId = nodeLangTextRecord.nodeId;
		record.language = nodeLangTextRecord.language;
		record.displayName = nodeLangTextRecord.displayName;
		record.comment = nodeLangTextRecord.comment;
	}

	void setTrusted(int nodeId, String language, String displayName, String comment) {
		record.nodeId = nodeId;
		record.language = language;
		record.displayName = displayName;
		record.comment = comment;
	}

	public boolean set(int nodeId, String language, String displayName, String comment) {
		if (loadNodeTextsByIdLang(this, nodeId, language)) {
			OsmtNodeLangText.updateNodeTexts(this, displayName, comment);
			return true;
		}
		record.nodeId = nodeId;
		record.language = language;
		record.displayName = displayName;
		record.comment = comment;
		return tryInsertAsNewNodeText(this);
	}

	public boolean set(OsmtNodeLangTextRecord nodeLangTextRecord) {
		return set(nodeLangTextRecord.nodeId, nodeLangTextRecord.language,
				nodeLangTextRecord.displayName, nodeLangTextRecord.comment);
	}

	private static void updateNodeTexts(final OsmtNodeLangText nodeLangText,
			final String displayName, final String comment) {
		final ContentValues contentValues = new ContentValues();

		if (displayName != null && !comment.equals(nodeLangText.record.displayName)) {
			contentValues.put(COLUMN_DISPLAY_NAME, displayName);
		}
		if (comment != null && !comment.equals(nodeLangText.record.comment)) {
			contentValues.put(COLUMN_COMMENT, comment);
		}

		if (contentValues.size() > 0) {
			final String whereClause = String.format("%s='%d' AND %s='%s'", COLUMN_NODE_ID,
					Integer.valueOf(nodeLangText.record.nodeId), COLUMN_LANGUAGE,
					nodeLangText.record.language);
			nodeLangText.osmtDatabase.update(nodeLangText, contentValues, whereClause, null);
		}

	}

	/**
	 * Asks the database for the id-associated diaplay_name and comment in the
	 * preferred language. If there is no comment in this language, this method
	 * delivers the comment that match the applications language. If there is
	 * still no such comment or display_name, it try to find an English command.
	 * Otherwise any comment will returned.
	 * 
	 * @param osmtData The database context.
	 * @param nodeId The id of the node.
	 * @param preferedLanguage The language you prefer
	 * @return The most appropriate language dependent texts, or null, if
	 *         nothing fit.
	 */
	static OsmtNodeLangTextRecord getBestFittingNodeLangById(final OsmtData osmtData,
			final int nodeId, String preferedLanguage) {

		final String lookupById = String.format("%s='%s'", COLUMN_NODE_ID,
				Integer.valueOf(nodeId));
		final String[] selectionCols = new String[] { COLUMN_LANGUAGE, COLUMN_DISPLAY_NAME,
				COLUMN_COMMENT };
		final OsmtQuery query = new OsmtQuery(TABLE, selectionCols, lookupById);
		final HashMap<String, OsmtNodeLangTextRecord> localizedTexts = new HashMap<String, OsmtNodeLangTextRecord>();
		final boolean found = ((OsmtDataImpl) osmtData).getDatabase().query(query,
				new OnObtainCursorListener() {

					@Override
					public boolean onObtainCursor(Cursor cursor) {
						if (cursor.moveToFirst()) {
							final int columnLangPosition = OsmtDatabaseUtils
									.detectColumnIndexOfCursorByName(cursor, COLUMN_LANGUAGE);
							final int columnDisplayNamePosition = OsmtDatabaseUtils
									.detectColumnIndexOfCursorByName(cursor,
											COLUMN_DISPLAY_NAME);
							final int columnCommentPosition = OsmtDatabaseUtils
									.detectColumnIndexOfCursorByName(cursor, COLUMN_COMMENT);
							do {
								final OsmtNodeLangTextRecord langRecord = new OsmtNodeLangTextRecord();
								langRecord.nodeId = nodeId;
								langRecord.language = cursor.getString(columnLangPosition);
								langRecord.displayName = cursor
										.getString(columnDisplayNamePosition);
								langRecord.comment = cursor.getString(columnCommentPosition);
								localizedTexts.put(cursor.getString(columnLangPosition),
										langRecord);
							} while (cursor.moveToNext());
							return true;
						}
						return false;
					}
				});
		// pick the display_name and comment that best fitting
		if (found) {
			if (preferedLanguage != null && localizedTexts.containsKey(preferedLanguage)) {
				final OsmtNodeLangTextRecord result = localizedTexts.get(preferedLanguage);
				if (StrUtils.isNotEmpty(result.displayName)
						|| StrUtils.isNotEmpty(result.comment))
					return result;
			}
			if (localizedTexts.containsKey(((OsmtDataImpl) osmtData).getAppLanguage())) {
				final OsmtNodeLangTextRecord result = localizedTexts
						.get(((OsmtDataImpl) osmtData).getAppLanguage());
				if (StrUtils.isNotEmpty(result.displayName)
						|| StrUtils.isNotEmpty(result.comment))
					return result;
			}
			if (localizedTexts.containsKey(OsmtDataImpl.getDefaultLanguage())) {
				final OsmtNodeLangTextRecord result = localizedTexts.get(OsmtDataImpl
						.getDefaultLanguage());
				if (StrUtils.isNotEmpty(result.displayName)
						|| StrUtils.isNotEmpty(result.comment))
					return result;
			}
			for (String language : localizedTexts.keySet()) {
				return localizedTexts.get(language);
			}

		}
		return null;
	}

	private static boolean loadNodeTextsByIdLang(final OsmtNodeLangText featureLangText,
			final int nodeId, final String language) {

		final String lookupByKeyValue = String.format("%s='%d' AND %s='%s'", COLUMN_NODE_ID,
				Integer.valueOf(nodeId), COLUMN_LANGUAGE, language);
		final String[] selectionCols = new String[] { COLUMN_DISPLAY_NAME, COLUMN_COMMENT };
		final OsmtQuery query = new OsmtQuery(TABLE, selectionCols, lookupByKeyValue);
		final boolean featureFound = featureLangText.osmtDatabase.query(query,
				new OnObtainCursorListener() {

					@Override
					public boolean onObtainCursor(Cursor cursor) {
						if (cursor.moveToFirst()) {
							featureLangText.setTrusted(nodeId, language, cursor.getString(0),
									cursor.getString(1));
							return true;
						}
						return false;
					}
				});
		return featureFound;
	}

	private static boolean tryInsertAsNewNodeText(final OsmtNodeLangText featureLangText) {
		final ContentValues contentValues = new ContentValues();
		contentValues.put(COLUMN_NODE_ID, featureLangText.record.nodeId);
		contentValues.put(COLUMN_LANGUAGE, featureLangText.record.language);
		contentValues.put(COLUMN_DISPLAY_NAME, featureLangText.record.displayName);
		contentValues.put(COLUMN_COMMENT, featureLangText.record.comment);
		return featureLangText.osmtDatabase.insertRecord(featureLangText, contentValues);
	}

	@Override
	public String getTableName() {
		return TABLE;
	}
}
